﻿
Imports System.Net
Imports System.Net.Sockets
Imports osi.root.constants
Imports osi.root.connector
Imports osi.root.envs
Imports osi.root.lock
Imports osi.root.formation
Imports osi.root.utils
Imports osi.root.procedure
Imports osi.service.commander

Partial Public Class accepter
    Private Class adapter
        Private ReadOnly ppts As vector(Of powerpoint)
        Private ReadOnly v4 As listener
        Private ReadOnly v6 As listener
        Private ReadOnly accepting As atomic_int
        Private l As duallock
        Private max_connecting As UInt32

        Public Sub New(ByVal port As UInt16)
            v4 = New listener(IPAddress.Any, port)
            v6 = New listener(IPAddress.IPv6Any, port)
            ppts = New vector(Of powerpoint)()
            accepting = New atomic_int()
            AddHandler v4.accepted, AddressOf accepted
            AddHandler v6.accepted, AddressOf accepted
        End Sub

        Public Sub attach(ByVal p As powerpoint)
            assert(Not p Is Nothing)
            assert(Not v4.valid OrElse p.port = v4.port())
            assert(Not v6.valid OrElse p.port = v6.port())
            v4.bind()
            v6.bind()
            l.writer_locked(Sub()
                                ppts.push_back(p)
                                If Not non_overflow_increment(max_connecting, p.max_connecting) Then
                                    max_connecting = max_uint32
                                End If
                            End Sub)
            AddHandler p.closing, Sub() detach(p)
        End Sub

        Private Sub detach(ByVal p As powerpoint)
            v4.release()
            v6.release()
            l.writer_locked(Sub()
                                For i As Int32 = 0 To ppts.size() - 1
                                    If object_compare(ppts(i), p) = 0 Then
                                        assert(ppts.erase(i))
                                        Return
                                    End If
                                Next
                                assert(False)
                            End Sub)
        End Sub

        Public Function attached_powerpoint_count() As Int32
            Return l.reader_locked(Function() ppts.size())
        End Function

        Private Function accept(ByVal c As TcpClient) As event_comb
            assert(Not c Is Nothing)
            Dim tp As pointer(Of powerpoint) = Nothing
            Dim ec As event_comb = Nothing
            Return New event_comb(Function() As Boolean
                                      If ppts.empty() Then
                                          Return False
                                      Else
                                          c.set_no_delay(True)
                                          tp = New pointer(Of powerpoint)()
                                          Dim p As powerpoint = Nothing
                                          p = ppts(0)
                                          assert(Not p Is Nothing)
                                          ec = verify_token(c, p, tp)
                                          Return waitfor(ec) AndAlso
                                                 goto_next()
                                      End If
                                  End Function,
                                  Function() As Boolean
                                      If Not ec.end_result() OrElse
                                         (+tp) Is Nothing OrElse
                                         Not (+tp).insert(c) Then
                                          If tcp_trace AndAlso
                                             (Not ec.end_result() OrElse
                                             (+tp) Is Nothing) Then
                                              raise_error("cannot find the assosiated powerpoint ",
                                                          "to insert the connection, close the connection ",
                                                          c.identity())
                                          End If
                                          c.shutdown()
                                          Return False
                                      Else
                                          Return goto_end()
                                      End If
                                  End Function)
        End Function

        Private Sub accepted(ByVal c As TcpClient)
            assert_begin(New event_comb(Function() As Boolean
                                            If (+accepting) >= max_connecting Then
                                                Return waitfor(constants.interval_ms.accepter_over_max_connecting)
                                            Else
                                                accepting.increment()
                                                Return goto_next()
                                            End If
                                        End Function,
                                        Function() As Boolean
                                            Return waitfor(accept(c)) AndAlso
                                                   goto_next()
                                        End Function,
                                        Function() As Boolean
                                            assert(accepting.decrement() >= 0)
                                            Return goto_end()
                                        End Function))
        End Sub

        Private Function verify_token(ByVal i() As Byte,
                                      ByVal o As pointer(Of Byte()),
                                      ByVal tp As pointer(Of powerpoint)) As event_comb
            Return New event_comb(Function() As Boolean
                                      Dim n As String = Nothing
                                      n = bytes_str(i)
                                      If l.reader_locked(
                                           Function() As Boolean
                                               For j As Int32 = 0 To ppts.size() - 1
                                                   assert(Not ppts(j) Is Nothing)
                                                   If strsame(ppts(j).token, n) Then
                                                       Return eva(tp, ppts(j))
                                                   End If
                                               Next
                                               Return False
                                           End Function) Then
                                          eva(o, i)
                                      Else
                                          If tcp_trace Then
                                              raise_error("no token ", n, " found, reject connection")
                                          End If
                                          eva(o, str_bytes(strcat("reject ", n)))
                                      End If
                                      Return goto_end()
                                  End Function)
        End Function

        'the powerpoint is not consistant with the one actually owns this connection,
        'the main trouble is the send_rate_sec and receive_rate_sec
        Private Function verify_token(ByVal c As TcpClient,
                                      ByVal p As powerpoint,
                                      ByVal tp As pointer(Of powerpoint)) As event_comb
            assert(Not p Is Nothing)
            Dim ec As event_comb = Nothing
            Return New event_comb(
                       Function() As Boolean
                           For i As Int32 = 0 To ppts.size() - 1
                               If String.IsNullOrEmpty(ppts(i).token) Then
                                   Return eva(tp, ppts(i)) AndAlso
                                          goto_end()
                               End If
                           Next

                           ec = +(New responder(c, p, New executor_wrapper(Function(i, o) verify_token(i, o, tp))))
                           Return waitfor(ec) AndAlso
                                  goto_next()
                       End Function,
                       Function() As Boolean
                           Return ec.end_result() AndAlso
                                  goto_end()
                       End Function)
        End Function
    End Class
End Class
